package reader;


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.StringTokenizer;

import value_object.SolutionVO;
import value_object.data.Acquisition;

/**
 * <p> This class is responsible for reading and writing a solution from and to a solution file
 * 
 * <p> The solution's information will be encapsulated by a SolutionVO object
 */

public class SolutionReader extends Reader {
	/**
	 * "Solutions" directory
	 */
	private static final String FILE_DIRECTORY = "Solutions";
	
	/**
	 * the solution file's name prefix
	 */
	private static final String FILE_NAME_PREFIX = "solution";
	
	public SolutionReader() {}	
	
	/**
	 * Overrides this method from the abstract one in the Reader superclass
	 * @return the solution file's directory
	 */
	@Override
	public String getFile_directory() { return FILE_DIRECTORY; }
	
	/**
	 * Overrides this method from the abstract one in the Reader superclass
	 * @return the prefix name of the solution file
	 */
	@Override
	public String getFile_name_prefix() { return FILE_NAME_PREFIX; }
	
	/**
	 * Reads a solution from the solution file
	 * @param x data set number
	 * @param y grid number
	 * @param z track number
	 * @return a SolutionVO object that contains the solution's information
	 * @throws IOException
	 */
	public SolutionVO readSolution(int x, int y, int z) throws IOException {
		
		BufferedReader bfReader = getBufferedReader(x, y, z);
		SolutionVO solution = new SolutionVO();
		
		String strLine;
		StringTokenizer tokenizer;
		
		// I. solution-information
	    strLine = bfReader.readLine();	    
	    tokenizer = new StringTokenizer(strLine, " ");
		solution.setData_set_number(Integer.parseInt(tokenizer.nextToken()));
		solution.setGrid_number(Integer.parseInt(tokenizer.nextToken()));
		solution.setTrack_number(Integer.parseInt(tokenizer.nextToken()));
		
		// II. acquisition-number
		strLine = bfReader.readLine();
		int acquisition_number = Integer.parseInt(strLine);
		
		// III. acquisitions
		for (int i = 0; i < acquisition_number; i++) {
			addAcquisitionTo(solution, bfReader);
		}
		
		//close buffered reader
		bfReader.close();
		
		return solution;
	}
	
	/**
	 * writes a solution (object) into the solution file
	 * @param solution SolutionVO object
	 * @throws IOException
	 */
	public void writeSolution(SolutionVO solution) throws IOException {
		int x = solution.getData_set_number();
		int y = solution.getGrid_number();
		int z = solution.getTrack_number();
		
		BufferedWriter bfWriter = getBufferedWriter(x, y, z);
		
		// I. solution-information
	    bfWriter.write(x + " " + y + " " + z + "\n");
		
		// II. acquisition-number
		bfWriter.write(solution.getAcquisitionList().size() + "\n");
		
		// III. acquisitions
		for (int i = 0; i < solution.getAcquisitionList().size(); i++) {
			writeAnAcquisition(solution.getAcquisitionList().get(i), bfWriter);
		}
		
		//close buffered writer
		bfWriter.close();
	}
	
	/**
	 * Writes an acquisition (object) to the solution file
	 * @param acquisition Acquisition object
	 * @param bfWriter Buffered writer
	 * @throws IOException
	 */
	private void writeAnAcquisition(Acquisition acquisition, BufferedWriter bfWriter) 
		throws IOException {
		
		bfWriter.write(acquisition.getStrip_index() + " " + acquisition.getAcquisition_direction() + "\n");
	}
	
	/**
	 * Reads an acquisition from the solution file, then adds it to a solution (object)
	 * @param solution SolutionVO object
	 * @param bfReader Buffered reader
	 * @throws IOException
	 */
	private void addAcquisitionTo(SolutionVO solution, BufferedReader bfReader)
			throws IOException {
		String strLine = bfReader.readLine();
		StringTokenizer tokenizer = new StringTokenizer(strLine, " ");
		
		Acquisition acquisition = new Acquisition();
		acquisition.setStrip_index(Integer.parseInt(tokenizer.nextToken()));
		acquisition.setAcquisition_direction(Integer.parseInt(tokenizer.nextToken()));
		
		solution.addAcquisition(acquisition);
	}
}
